package service

import (
	"encoding/json"
	"errors"
	"strconv"
	"time"

	"gorm.io/gorm"

	"collecter/app/cache"
	"collecter/app/common/enum"
	"collecter/app/common/helper"
	"collecter/app/model"
)

type Authorize struct {
	Account     string
	AuthType    string
	AccountType string
	VCode       int
	Password    string
}

// LIType
//
//	LIType
//	@Description: 登录返回数据类型
type LIType struct {
	AccessToken   string `json:"access_token,omitempty"`
	RefreshToken  string `json:"refresh_token,omitempty"`
	AccessExpire  int64  `json:"access_expire,omitempty"`
	RefreshExpire int64  `json:"refresh_expire,omitempty"`
}

// PmType
//
//	pmType
//	@Description: 账号激活时传参的格式
type PmType struct {
	Account      string `json:"account"`
	ActivateCode string `json:"activate_code"`
	RegisterTime string `json:"register_time"`
}

func NewAuthorize() *Authorize {
	return &Authorize{}
}

func (a *Authorize) WithAccount(account string) *Authorize {
	a.Account = account
	return a
}

func (a *Authorize) WithAuthType(authType string) *Authorize {
	a.AuthType = authType
	return a
}

func (a *Authorize) WithAccountType(accountType string) *Authorize {
	a.AccountType = accountType
	return a
}

func (a *Authorize) WithVcode(vcode int) *Authorize {
	a.VCode = vcode
	return a
}

func (a *Authorize) WithPassword(password string) *Authorize {
	a.Password = password
	return a
}

func (a *Authorize) Register() error {
	user := model.Users{}

	if "vcode" == a.AuthType {
		vcode := NewVcode(a.Account, "register")
		if err := vcode.VerifyCode(strconv.Itoa(a.VCode)); err != nil {
			return err
		}
		if h, err := helper.GeneratePassword(enum.USER_DEFAULT_PASSWORD); err != nil {
			return errors.New("注册失败：" + err.Error())
		} else {
			user.Password = h
		}
	} else {
		if h, err := helper.GeneratePassword(a.Password); err != nil {
			return errors.New("注册失败：" + err.Error())
		} else {
			user.Password = h
		}
	}

	if err := helper.Db.Where("account = ? or mobile = ? or email = ?", a.Account, a.Account, a.Account).First(&user).Error; err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			return err
		}
	} else {
		return errors.New("账号已经存在")
	}
	user.Account = a.Account

	user.LastModifyPasswordTime = time.Now().Unix()
	user.IsActivate = 2
	user.Status = enum.STATUS_ENABLED
	isEmail := helper.RegExpVerify(a.Account, "email")
	isMobile := helper.RegExpVerify(a.Account, "mobile")
	if isEmail {
		user.Email = a.Account
	} else if isMobile {
		user.Mobile = a.Account
	}
	if err := helper.Db.Create(&user).Error; err != nil {
		return err
	}
	// 触发用户注册事件
	helper.EventTrigger(enum.EVENT_USER_REGISTER, user.Id, "")
	return nil
}

func (a *Authorize) Login() (LIType, error) {
	var w string
	var info LIType
	if "email" == a.AccountType {
		w = "email = ?"
	} else if "mobile" == a.AccountType {
		w = "mobile = ?"
	} else {
		w = "account = ?"
	}
	w += " and status = 1"
	user := model.Users{Account: a.Account}
	if err := helper.Db.Where(w, a.Account).First(&user).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return info, errors.New("登录失败：账号或者密码错误")
		}
		return info, err
	}
	if user.IsActivate != 1 {
		return info, errors.New("登录失败：账号未激活")
	}

	if "vcode" == a.AuthType {
		vcode := NewVcode(a.Account, "login")
		if err := vcode.VerifyCode(strconv.Itoa(a.VCode)); err != nil {
			return info, err
		}
	} else {
		if err := helper.VerifyHashed(a.Password, user.Password); err != nil {
			return info, errors.New("登录失败：账号或者密码错误")
		}
	}

	t := time.Now().Unix()

	if t-user.LastModifyPasswordTime >= enum.PASSWORD_EXPIRE {
		return info, errors.New("密码过期请重置")
	}
	accessToken := helper.GenerateToken(a.Account, "access_token")
	refreshToken := helper.GenerateToken(a.Account, "refresh_token")

	user.RefreshToken = refreshToken
	user.TokenExpired = t + enum.REFRESH_TOKEN_EXPIRE
	if err := helper.Db.Updates(&user).Error; err != nil {
		return info, err
	}

	user.Password = ""
	cacheKey := enum.USER_LOGIN_INFO + refreshToken
	var userJson []byte
	if val, err := json.Marshal(user); err != nil {
		return info, err
	} else {
		userJson = val
	}
	if err := cache.Cacher.Set(cacheKey, userJson, enum.REFRESH_TOKEN_EXPIRE); err != nil {
		return info, err
	}
	cacheKey = enum.ACCESS_TOKEN + accessToken
	if err := cache.Cacher.Set(cacheKey, refreshToken, enum.ACCESS_TOKEN_EXPIRE); err != nil {
		return info, err
	}

	info.AccessToken = accessToken
	info.RefreshToken = refreshToken
	info.AccessExpire = t + enum.ACCESS_TOKEN_EXPIRE
	info.RefreshExpire = user.TokenExpired

	// 触发用户注册事件
	helper.EventTrigger(enum.EVENT_USER_LOGIN, user.Id, "")
	return info, nil
}

func (p *PmType) AccountActivate() error {
	var user model.Users
	user.Account = p.Account
	if err := helper.Db.Where(&user).First(&user).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("账号不存在")
		}
		return err
	}
	regTime, _ := strconv.Atoi(p.RegisterTime)
	if int64(regTime) != user.CreatedAt {
		return errors.New("账号激活失败")
	}
	cacheKey := enum.USER_ACTIVATE_CODE + p.Account
	if err := cache.Cacher.Has(cacheKey); err != nil {
		return errors.New("账号激活失败")
	}
	if activateCode, err := cache.Cacher.GetString(cacheKey, true); err != nil {
		return err
	} else if activateCode != p.ActivateCode {
		return errors.New("账号激活失败")
	}
	user.IsActivate = 1
	if err := helper.Db.Updates(&user).Error; err != nil {
		return err
	}
	return nil
}

func (a *Authorize) Bind(sendCodeAccount string) error {
	var user model.Users
	user.Account = a.Account
	user.Status = enum.STATUS_ENABLED
	if err := helper.Db.Where(&user).First(&user).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("账号不存在")
		}
		return err
	}
	if err := helper.VerifyHashed(a.Password, user.Password); err != nil {
		return errors.New("绑定失败：账号或者密码错误")
	}
	if helper.RegExpVerify(sendCodeAccount, "mobile") {
		user.Mobile = sendCodeAccount
		var otherUser model.Users
		if helper.Db.Where("mobile = ? and status != -1", sendCodeAccount).First(&otherUser).Error == nil {
			return errors.New("绑定失败：账号已经被使用")
		}
	} else if helper.RegExpVerify(sendCodeAccount, "email") {
		var otherUser model.Users
		if helper.Db.Where("email = ? and status != -1", sendCodeAccount).First(&otherUser).Error == nil {
			return errors.New("绑定失败：账号已经被使用")
		}
		user.Email = sendCodeAccount
	}
	vcode := NewVcode(sendCodeAccount, "bindAccount")
	if err := vcode.VerifyCode(strconv.Itoa(a.VCode)); err != nil {
		return err
	}
	if err := helper.Db.Updates(&user).Error; err != nil {
		return err
	}
	if 2 == user.IsActivate {
		// 触发用户注册事件
		helper.EventTrigger(enum.EVENT_USER_REGISTER, user.Id, "")
	}
	return nil
}

func (a *Authorize) ResetPassword() error {
	vcode := NewVcode(a.Account, "resetPassword")
	if err := vcode.VerifyCode(strconv.Itoa(a.VCode)); err != nil {
		return err
	}
	user := model.Users{}
	w := "(account = ? or mobile = ? or email = ?) and status = ?"
	if err := helper.Db.Where(w, a.Account, a.Account, a.Account, enum.STATUS_ENABLED).First(&user).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("用户不存在")
		}
		return err
	}
	if val, err := helper.GeneratePassword(a.Password); err != nil {
		return err
	} else {
		user.Password = val
	}
	user.LastModifyPasswordTime = time.Now().Unix()
	return helper.Db.Updates(&user).Error
}
